classdef asynctrcircuit < qucstrans
    % asynchonous circuit solver for use with the ode integrator routines
    % based on an interface to the qucs transient circuit solvers
    %
    %

    % Copyright Richard Crozier 2013, 2014

    properties (SetAccess = private, GetAccess = public)

        % used to determine if we need to accept or reject a step before
        % continuing
        step_solved;

    end


    methods

        function this = asynctrcircuit(netlist)

            this = this@qucstrans(netlist);

        end

        function init(this, tstart, firstdelta)
            % initialises the circuit solver

            this.cppcall('init_async', tstart, firstdelta);

            this.isinitialised = true;
            
            this.step_solved = false;

        end
        
        function stepsolve(this, t)
            % solves an asynchronous step at the supplied time
            %
            % Syntax
            %
            % stepsolve(this, t)
            %
            % Input
            %
            %   t - the time point at which the circuit simulation is to be
            %   solved
            %
            % Description
            %
            % This function causes the qucs solvers to attempt to solve the
            % circuit at the time t. The result is stored internally, and
            % can be retrieved with the getsolution method. The solution is
            % not added to the history of time steps used by the circuit
            % integrators. To add the solution to the history and move on
            % to the next step, the acceptstep_sync function must be used.
            %

            if this.step_solved == true
                error ('A time step has already been solved and must be accepted or rejected before solving another.');
            end
            
            if ~isscalar(t)
                error('t must be a scalar.');
            end

            this.cppcall('stepsolve_async', t);

            this.step_solved = true;
            
        end
        
        function [sol, NM] = getsolution(this)
            % retrieves the last solution generated by the circuit solver
            %
            % Syntax
            %
            % [sol, NM] = getsolution(this)
            %
            % Description
            %
            % getsolution returns an vector containing the nodal voltages
            % and branch currents at the last solution generated by a call
            % to stepsolve acceptstep, or just initialisation. The number
            % of nodal voltages and branch currents respectively are
            % returned in the two element vector NM.
            %

            [sol, NM] = this.cppcall('getsolution');

        end
        
        function acceptstep(this, t)
            % recalculates and accepts a time step solution into the
            % internal history of solutions for the circuit integrators
            %
            % Syntax
            %
            % acceptstep(this, t)
            %
            % Input
            %
            %   t - the time point at which the circuit is to be
            %     recalculated and added to the solution history
            % 

            if this.step_solved == false
                
                if nargin < 2
                    error ('If no step has been solved, you must supply a time step at which to calculate it.');
                end
                    
                % solve the step if it hasn't been done already
                stepsolve(this, t);
            end

            this.cppcall('acceptstep_async');
            
            % reset the step_solved flag
            this.step_solved = false;

        end
        
        function rejectstep(this)
            % rejects an asynchronous step, resetting the internal history
            % to the last accepted step
            %
            % Syntax
            %
            % rejectstep(this)
            %

            this.cppcall('rejectstep_async');
            
            % reset the step_solved flag
            this.step_solved = false;

        end
        
    end
    
    
    methods(Static)
        
        function status = odeoutputfcn(t, y, flag, qtr_async)
            % static method for updating the asynchronous circuit on each
            % time step of an ode solution
            %
            % Syntax
            %
            % status = odeoutputfcn(t, y, flag, qtr_async)
            %
            % Description
            %
            % This function must be called as the output function, or
            % within the output function of an ode solution incorporating
            % the synchronous circuit solver. See the help for odeset.m for
            % more details on the ode solver OutputFcn option. 
            %
            % 
            
            status = 0;
            
            if isempty(flag)
                % solve and accept the time step into the circuit solution
                % history
                qtr_async.acceptstep(t);

            elseif strcmp(flag, 'init')
                % initialise the circuit
%                 qtr_async.init(t(1));

            elseif strcmp(flag, 'done')
                
            end
            
        end

    end

end